package com.jf.pay.ali;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.alipay.api.internal.util.AlipaySignature;
import com.jf.pay.DateUtils;
import com.jf.utils.Result;
import com.jf.utils.ResultMap;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;
import net.sf.json.JSONObject;


/**
 * 支付宝api
 * @author Administrator
 *
 */
public class PayAPI extends Controller{
	/**
	 * 完整的符合支付宝参数规范的订单信息"http://ik351zwypv.proxy.qqbrowser.cc/service/payApi/getPayNotify"
	 * @throws UnsupportedEncodingException 
	 * @throws Exception 
	 * @param orderid 订单号
	 * @param subject 标题
	 * @param body
	 * @param price 金额
	 * @param type 商品类型  1-实体商品，0-虚拟商品
	 * @param url 回调地址
	 * @throws UnsupportedEncodingException
	 * @throws Exception
	 */
	public static String getPayInfo(String orderid, String subject, String body, String price,String type,String url) throws UnsupportedEncodingException, Exception {
		//String orderInfo = getOrderInfo(orderid, subject, body, price, url);
		BigDecimal bd = new BigDecimal(price);   
		bd = bd.setScale(2,BigDecimal.ROUND_HALF_UP); 
		Map<String,String> map = new HashMap<String,String>();
		map.put("seller_id", AlipayConfig.seller);
		map.put("total_amount", bd.toString());
		map.put("subject", subject);
		map.put("out_trade_no", orderid);
		map.put("product_code", "QUICK_MSECURITY_PAY");
		map.put("goods_type",type);
		JSONObject obj = JSONObject.fromObject(map);
		System.out.println(obj);
		String notify_url = url;
		String timestamp = DateUtils.getDateTime();
		String orderInfo = "app_id="+AlipayConfig.partner+"&biz_content="+obj+"&charset=utf-8&method=alipay.trade.app.pay&notify_url="+notify_url+"&sign_type=RSA2&timestamp="+timestamp+"&version=1.0";
		System.out.println("orderInfo:----------"+orderInfo);
		/**
		 * 特别注意，这里的签名逻辑需要放在服务端，切勿将私钥泄露在代码中！
		 */
		String sign =null;
		String rsaSign2 = AlipaySignature.rsa256Sign(orderInfo, AlipayConfig.private_key, "utf-8");
		System.out.println("sign----------"+rsaSign2);
		try {
			/**
			 * 仅需对sign 做URL编码
			 */
			sign = URLEncoder.encode(rsaSign2, "UTF-8");
			System.out.println("sign:编码----------"+sign);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		/**
		 * 完整的符合支付宝参数规范的订单信息
		 */
		final String payInfo = orderInfo + "&sign=" + sign ;
		
		System.out.println(payInfo);
		return payInfo;
	}
	
	/**
	 * 支付宝回调
	 * @throws UnsupportedEncodingException 
	 */
	@SuppressWarnings("unused")
	public void getPayNotify() throws UnsupportedEncodingException {
		//获取支付宝POST过来反馈信息
		Map<String,String> params = new HashMap<String,String>();
		Map<String, String[]> requestParams = getParaMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ",";
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		//商户订单号	
		String out_trade_no = new String(getPara("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

		//支付宝交易号	
		String trade_no = new String(getPara("trade_no").getBytes("ISO-8859-1"),"UTF-8");
		//交易状态
		String trade_status = new String(getPara("trade_status").getBytes("ISO-8859-1"),"UTF-8");
		//买家支付宝账号
		String buyer_email = new String(getPara("buyer_email").getBytes("ISO-8859-1"),"UTF-8");
		//交易金额
		String price = new String(getPara("price").getBytes("ISO-8859-1"),"UTF-8");
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//

		if(AlipayNotify.verify(params)){//验证成功
			//////////////////////////////////////////////////////////////////////////////////////////
			//请在这里加上商户的业务逻辑程序代码

			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
			
			if(trade_status.equals("TRADE_FINISHED")){
				//判断该笔订单是否在商户网站中已经做过处理
					//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
					//如果有做过处理，不执行商户的业务程序
					
				//注意：
				//退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
				//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
			} else if (trade_status.equals("TRADE_SUCCESS")){
				//判断该笔订单是否在商户网站中已经做过处理
					//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
					//如果有做过处理，不执行商户的业务程序
					
				//注意：
				//付款完成后，支付宝系统发送该交易状态通知
				//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
				
				
			}

			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
				
			renderText("success");//请不要修改或删除

		}else{//验证失败
			renderText("fail");
		}
	}
	
	/**
	 * 支付余额和支付密码查询
	 * 获得参数：用户userPhone
	 * 完成动作：a.查询余额，
	 * 			b.查询支付密码是否存在
	 * 			
	 * 返回信息：a.余额
	 * 			b.有/无 支付密码
	 * 注意事项：事物控制 
	 * 			收集异常信息：数据库异常，网络异常
	 * 
	 */
	public void findPay(){
		Map<String,Object> map = new HashMap<String,Object>();
		//获取用户手机号
		String userPhone =getPara("phone");
		//查询余额和支付密码
		Record user = null;
		try{
		user = Db.find("select balance,pay_pwd from t_user where phone = ?", userPhone).get(0);
		}catch(Exception e){
			renderJson(new ResultMap("0","服务器繁忙",map));
			return; 
		}
		
		//取出余额和支付密码
		String balance = user.getStr("balance");
		String payPwd = user.getStr("pay_pwd");
		
		//判断是否有支付密码
		if(null!=payPwd&&""!=payPwd){
			map.put("balance",balance);
			map.put("isPayPwd","1");
			renderJson(new ResultMap("1","已设置支付密码",map));
		}else{
			map.put("balance",balance.toString());
			map.put("isPayPwd","0");
			renderJson(new ResultMap("1","未设置支付密码",map));
		}
	}
	
	/**
	 * 创建支付密码
	 * 获得参数：用户userPhone,输入的payPwd
	 * 完成动作：a.给用户表插入支付密码
	 * 返回信息：插入成功/失败
	 * 注意事项：事物控制,收集异常信息
	 * 
	 */
	
	@Before(Tx.class)
	public void insertPayPwd(){
		//获取用户的手机号	
		String phone = getPara("phone"); 
		//获取用户输入的支付密码
		String payPwd = getPara("payPwd");
		
		//插入把支付密码插入到t_user 表中
		try{
			int update = Db.update("update t_user set pay_pwd = ? where phone = ?", payPwd,phone);
			
			//判断是否插入成功
			if(0==update){
				throw new RuntimeException();
			}
			//创建result工具类 返回数据
		}catch(Exception e){
			
			
			//插入失败则回滚数据
			try {
				DbKit.getConfig().getConnection().rollback();
			} catch (SQLException e1) {
				renderJson( new Result("0","服务器繁忙",null));
			}
			return;
		}finally{
			renderJson( new Result("1","支付密码设置失败",null));
		}
		renderJson( new Result("1","支付密码设置成功",null));
	}
	
	/**
	 * 聊天室打赏动作
	 * 获得参数：用户userPhone 被打赏人getPhone 打赏金额 money
	 * 完成动作：a.打赏用户余额减少  数额为打赏金额 
	 * 		    b.被打赏用户余额增加  数额为打赏金额
	 * 			c.创建a交易信息
	 * 			d.创建b交易信息
	 * 返回信息：交易完成信息
	 * 注意事项：a.b.两个动作需要在一个事务内完成，注意收集异常信息。
	 * 
	 */
	 public void payTour(String payPhone,String getPhone,Double money){
		 
		 
	 }
	 
	 /**
	  * 用户修改支付密码
	  * 获得参数：a.用户手机号phone
	  * 		 b.用户旧的支付密码
	  * 		 c.用户新的支付密码
	  * 完成动作：  验证旧的支付密码，
	  *           修改新的支付密码
	  * 返回信息：成功/失败
	  * 注意事项：修改操作需要进行事务控制
	  */
	 @Before(Tx.class)
	 public void changePayPwd(){
		 //获取参数
		 String phone = getPara("phone");
		 String oldPayPwd = getPara("oldPayPwd");
		 String newPayPwd = getPara("newPayPwd");
		 
		 try{
			 //通过手机号查询用户支付密码
			 List<Record> find = Db.find("select pay_pwd from t_user where phone = ?",phone);
			 Record record = find.get(0);
			 String payPwd = record.getStr("pay_pwd");
		 	if(payPwd.equals(oldPayPwd)){
			//如果判断成功则修改密码
				 Db.update("update t_user set pay_pwd = ? where phone = ?",newPayPwd,phone);
				 
			 }else{
		    //判断失败则return 
			 renderJson(new Result("1","您输入的支付密码有误，请从新输入。",null));
			 return;
			 }
		 }catch(Exception e){
			 //获取异常 回滚
			 try {
					DbKit.getConfig().getConnection().rollback();
				} catch (SQLException e1) {
					e.printStackTrace();
				}
			 	renderJson( new Result("0","服务器繁忙",null));
				return;
		 }
		 //最后返回成功信息
		 renderJson(new Result("1","您的支付密码修改成功",null));
		 
	 }
	 
	 /**
	  * 验证支付密码
	  * 获得参数:a.用户手机号phone
	  * 		b.用户支付密码payPwd
	  * 完成动作：验证支付密码是否正确
	  * 返回信息：对/错
	  * 注意事项：不需要验证空值
	  * 
	  */
	 public void verifyPayPwd(){
		//获取用户的手机号	
			String phone = getPara("phone"); 
			//获取用户输入的支付密码
			String payPwd = getPara("payPwd");
			
			//通过手机号查询用户支付密码
			try{
				 List<Record> find = Db.find("select pay_pwd from t_user where phone = ?",phone);
				 Record record = find.get(0);
				 String findPayPwd = record.getStr("pay_pwd");
				 
				 //验证支付密码
				 if(!payPwd.equals(findPayPwd)){
					 renderJson(new Result("1","支付密码验证失败",null));
				 }
			 }catch(Exception e){
				 //获取异常 回滚
				 try {
						DbKit.getConfig().getConnection().rollback();
					} catch (SQLException e1) {
						e.printStackTrace();
					}
				 	renderJson( new Result("0","服务器繁忙",null));
					return;
			 }
			 renderJson(new Result("1","支付密码验证成功",null));
	 }
	 
	
	/**
	 * create the order info. 创建订单信息
	 * 
	 */
	@SuppressWarnings("unused")
	private static String getOrderInfo(String orderid, String subject, String body, String price, String url) {

		// 签约合作者身份ID
		String orderInfo = "app_id=" + "\"" + AlipayConfig.partner + "\"";

		// 签约卖家支付宝账号
		orderInfo += "&seller_id=" + "\"" + AlipayConfig.seller + "\"";

		// 商户网站唯一订单号
		orderInfo += "&out_trade_no=" + "\"" + orderid + "\"";

		// 商品名称
		orderInfo += "&subject=" + "\"" + subject + "\"";

		// 商品详情
		orderInfo += "&body=" + "\"" + body + "\"";

		// 商品金额
		orderInfo += "&total_amount=" + "\"" + price + "\"";

		// 服务器异步通知页面路径
		orderInfo += "&notify_url=" + "\"" + url + "\"";

//		// 服务接口名称， 固定值
//		orderInfo += "&service=\"mobile.securitypay.pay\"";
		orderInfo += "&method=\"alipay.mobile.public.menu.add\"";

		// 支付类型， 固定值
		orderInfo += "&payment_type=\"1\"";

		// 参数编码， 固定值
		orderInfo += "&_input_charset=\"utf-8\"";

		// 设置未付款交易的超时时间
		// 默认30分钟，一旦超时，该笔交易就会自动被关闭。
		// 取值范围：1m～15d。
		// m-分钟，h-小时，d-天，1c-当天（无论交易何时创建，都在0点关闭）。
		// 该参数数值不接受小数点，如1.5h，可转换为90m。
		orderInfo += "&it_b_pay=\"30m\"";

		// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
		// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";

		// 支付宝处理完请求后，当前页面跳转到商户指定页面的路径，可空
		orderInfo += "&return_url=\"m.alipay.com\"";

		// 调用银行卡支付，需配置此参数，参与签名， 固定值 （需要签约《无线银行卡快捷支付》才能使用）
		// orderInfo += "&paymethod=\"expressGateway\"";

		return orderInfo;
	}
	
//	/**
//	 * get the out_trade_no for an order. 生成商户订单号，该值在商户端应保持唯一（可自定义格式规范）
//	 * 
//	 */
//	private String getOutTradeNo() {
//		SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
//		Date date = new Date();
//		String key = format.format(date);
//
//		Random r = new Random();
//		key = key + r.nextInt();
//		key = key.substring(0, 15);
//		return key;
//	}

	/**
	 * get the sign type we use. 获取签名方式
	 * 
	 */
	@SuppressWarnings("unused")
	private static String getSignType() {
		return "sign_type=\"RSA\"";
	}
	
	
	
}
